﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SomeGame.Actors.Components.Movement;
using SomeGame.Zones;

namespace SomeGame.Actors.Components.State {

	public class ZombieStateMachine : ActorComponent {

	    private State PreviousState = State.Null;
		public State CurrentState = State.Null;
		private Animation CurrentAnimation; // Swapped out and updated based on state.
		private readonly ZombieMovement Movement; // CurrentDirection and CurrentSpeed set based on state.
		private readonly Appearance Appearance; // SpriteEffects set based on state.
		private readonly IDictionary<State, Animation> Animations = new Dictionary<State, Animation>();

		public ZombieStateMachine(ZombieMovement movement, Appearance appearance, Animation idle, Animation walking, Animation inPain, Animation dying, Animation dead, Animation gibbed, Animation goo) {
			Animations.Add(State.Idle, idle);
			Animations.Add(State.Walking, walking);
			Animations.Add(State.InPain, inPain);
			Animations.Add(State.Dying, dying);
            Animations.Add(State.Dead, dead);
            Animations.Add(State.Gibbed, gibbed);
            Animations.Add(State.Goo, goo);
			Movement = movement;
			Appearance = appearance;
			SetCurrentState(State.Idle);
		}

        /// <summary>
        /// Here you can make changes before the old state phases out,
        /// and you can make changes as the new state takes hold.
        /// </summary>
	    public void SetCurrentState(State nextState) {
            if (CurrentState == nextState) {
                return;
            }
			// Actions based on what the Zombie IS doing right now.
			switch (CurrentState) {
				case State.Idle:
                    if (nextState == State.InPain) {
                        PreviousState = CurrentState;
                    }
					break;
                case State.Walking:
                    if (nextState == State.InPain) {
                        PreviousState = CurrentState;
                    }
                    break;
				case State.InPain:
					break;
				case State.Dying:
					break;
				case State.Dead:
			        break;
				case State.Gibbed:
					break;
				case State.Goo:
			        break;
			}
			// Actions based on what the Zombie WILL BE doing after the transition.
			switch (nextState) {
				case State.Idle:
					Stop();
					break;
                case State.Walking:
			        FacingDirection direction = GameEngine.Random.Next(0, 2) == 0 ? FacingDirection.Left : FacingDirection.Right;
			        Movement.CurrentDirection = direction == FacingDirection.Right ? new Vector2(1, 0) : new Vector2(-1, 0);
			        Movement.CurrentSpeed = ZombieMovement.WALKING_SPEED;
			        Appearance.SpriteEffects = direction == FacingDirection.Right ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
                    break;
				case State.InPain:
                    Stop();
			        ZoneManager.CurrentZone.SoundEffectInstances["HumanPain"].Play();
					break;
				case State.Dying:
					Stop();
			        ZoneManager.CurrentZone.SoundEffectInstances["HumanDeath"].Play();
					break;
				case State.Dead:
					Stop();
					break;
				case State.Gibbed:
					Stop();
					break;
				case State.Goo:
					Stop();
					break;
			}
	        if (Animations.ContainsKey(nextState)) { // States are not required to have animations.
	            CurrentAnimation = Animations[nextState];
	            CurrentAnimation.SetInitialFrame();
	        }
	        CurrentState = nextState;
		}

		//=====( End Changing the CurrentState)=======

		private void Stop() {
			Movement.CurrentDirection = Vector2.Zero;
			Movement.CurrentSpeed = 0;
		}

		public override void Update(GameTime gameTime, bool parallax) {
			switch (CurrentState) {
				case State.InPain:
					if (CurrentAnimation.IsDoneShowingLastFrame()) {
					    SetCurrentState(PreviousState);
					}
					break;
				case State.Dying:
					if (CurrentAnimation.IsDoneShowingLastFrame()) {
					    SetCurrentState(State.Dead);
					}
					break;
				case State.Gibbed:
					if (CurrentAnimation.IsDoneShowingLastFrame()) {
					    SetCurrentState(State.Goo);
					}
					break;
			}
			CurrentAnimation.Update(gameTime, parallax);
			Movement.Update(gameTime, parallax);
		}

		public enum State {

            Null,
			Idle,
			Walking,
			Attacking,
			InPain,
			Dying,
			Dead,
			Gibbed,
			Goo

		}

	}

}